1 /* 2 * Hunt - a framework for web and console application based on Collie using Dlang development 3 * 4 * Copyright (C) 2015-2017 Shanghai Putao Technology Co., Ltd 5 * 6 * Developer: HuntLabs 7 * 8 * Licensed under the Apache-2.0 License. 9 * 10 */ 11 12 module hunt.text.conf; 13 14 import std.array; 15 import std.stdio; 16 import std.string; 17 import std.exception; 18 19 class INIFormatExceptionException : Exception 20 { 21 mixin basicExceptionCtors; 22 } 23 24 class Ini 25 { 26 this() 27 {} 28 29 this(string file) 30 { 31 setConfigFile(file); 32 } 33 34 //pragma(inline, true) 35 void setConfigFile(string file) 36 { 37 _fileName = file; 38 readConf(); 39 } 40 41 auto get(T = string)(string path, T def = T.init) 42 { 43 import std.conv; 44 string str = _element.getValue(path); 45 if(str.length == 0) 46 return def; 47 else 48 return to!T(str); 49 } 50 51 bool set(T)(string path, T value) 52 { 53 import std.conv; 54 if(path.length == 0) return false; 55 string[] list = split(path,'.'); 56 size_t len = list.length - 1; 57 auto ele = getElement(list[0..len]); 58 string key = list[len]; 59 if(key.length == 0) return false; 60 ele.values[key] = to!string(value); 61 return true; 62 } 63 64 pragma(inline, true) 65 bool save() 66 { 67 return saveToFile(_fileName); 68 } 69 70 pragma(inline, true) 71 bool saveAs(string fileName) 72 { 73 return saveToFile(fileName); 74 } 75 76 protected: 77 void readConf() 78 { 79 auto f = File(_fileName,"r"); 80 if(_element) 81 { 82 _element.destroy; 83 } 84 _element = new Element(); 85 if(!f.isOpen()) return; 86 scope(exit) f.close(); 87 Element ele = _element; 88 int line = 1; 89 while(!f.eof()) 90 { 91 scope(exit) line += 1; 92 string str = f.readln(); 93 str = strip(str); 94 if(str.length == 0) continue; 95 if(str[0] == '#' || str[0] == ';') continue; 96 auto len = str.length -1; 97 if(str[0] == '[' && str[len] == ']') 98 { 99 string section = str[1..len].strip; 100 string[] list = split(section,'.'); 101 ele = getElement(list); 102 continue; 103 } 104 auto site = str.indexOf("="); 105 enforce!INIFormatExceptionException((site > 0),format("the format is erro in file %s, in line %d",_fileName,line)); 106 string key = str[0..site].strip; 107 string value = str[site + 1..$].strip; 108 ele.values[key] = value; 109 } 110 } 111 112 113 Element getElement(in string[] list) 114 { 115 Element ele = _element; 116 size_t num = 1; 117 foreach (ref str ; list) 118 { 119 scope(exit) num += 1; 120 if(str.length == 0) continue; 121 auto tele = ele.elements.get(str, null); 122 if(tele is null) 123 { 124 tele = new Element; 125 tele.path = list[0..num].join('.'); 126 ele.elements[str] = tele; 127 } 128 ele = tele; 129 } 130 return ele; 131 } 132 133 bool saveToFile(string file) 134 { 135 if(file.length == 0) return false; 136 auto f = File(file,"w"); 137 if(!f.isOpen()) return false; 138 writeElement(&f,_element); 139 return true; 140 } 141 142 void writeElement(File * file, Element ele) 143 { 144 if(ele.path.length > 0) 145 { 146 file.writeln(format(";The section = %s",ele.path)); 147 file.writefln("[%s]",ele.path); 148 } 149 150 foreach(key,value; ele.values) 151 { 152 file.writefln("%s = %s",key,value); 153 } 154 file.writeln(""); 155 foreach(_,value; ele.elements) 156 { 157 writeElement(file,value); 158 } 159 } 160 161 private: 162 string _fileName; 163 Element _element; 164 } 165 166 alias Conf = Ini; 167 168 private: 169 final class Element 170 { 171 string[string] values; 172 173 Element[string] elements; 174 175 string path; 176 177 string getValue(string key) 178 { 179 if(key.length == 0) return string.init; 180 string[] list = split(key,'.'); 181 size_t len = list.length - 1; 182 Element ele = this; 183 for (size_t i = 0; i < len; ++i) 184 { 185 auto element = ele.elements.get(list[i], null); 186 if (element is null ) return string.init; 187 ele = element; 188 } 189 return ele.values.get(list[len], string.init); 190 } 191 } 192 193 unittest 194 { 195 string tbody = "[server] \nhost = 0.0.0.0 \nport = 8081 \n\n[upload_tmp_path]\ntempath = ./storage/tmp\n\n"; 196 tbody ~= "[route] \npath = ./config/router.conf \n\n[log] \nname = error,fatal,info\n\n[file_path]\nfilesDir = ./uploads\n;huioiujopp\n#guijj\n\n"; 197 tbody ~= "[route.tmp]\npath = hujjokp\n\n"; 198 auto f = File("tmp.conf","w"); 199 f.write(tbody); 200 f.close(); 201 Conf conf = new Conf("tmp.conf"); 202 string host = conf.get("server.host"); 203 assert(host == "0.0.0.0"); 204 ushort us = conf.get!ushort("server.port"); 205 assert(us == cast(ushort)8081); 206 host = conf.get("route.tmp.path"); 207 assert(host == "hujjokp"); 208 host = conf.get("upload_tmp_path.tempath"); 209 assert(host == "./storage/tmp"); 210 conf.set("aa.bb.cc.dd", 500); 211 assert(conf.saveAs("tmp.saveas.conf")); 212 }